/*
 *  Pedometer - Android App *  Copyright (C) 2009 Levente Bagi
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package br.unb.ida.midialab.pedparq;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteException;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;

public class Pedometer extends Activity {
	private static final String TAG = "Pedometer";
    private SharedPreferences mSettings;
    private PedometerSettings mPedometerSettings;
    private Utils mUtils;
    
    private long data;
    private long tempoParado = 0l;
    long tempoAtividade;
    Float velMedia;
    String status;
    
    private ProgressBar mProgress;
    private TextView mStepValueView;
    private TextView mPaceValueView;
    private TextView mDistanceValueView;
    private TextView mSpeedValueView;
    private TextView mCaloriesValueView;
    private Chronometer mTimeValueView;
    private TextView mTxTipoAtValueView;
    private ImageButton mBtTipoAtValueView;
    TextView mDesiredPaceView;
    private int mStepValue;
    private int mPaceValue;
    private float mDistanceValue;
    private float mSpeedValue;
    private int mCaloriesValue;
    private float mDesiredPaceOrSpeed;
    private int mMaintain;
    private boolean mIsMetric;
    @SuppressWarnings("unused")
	private float mMaintainInc;
    private boolean mQuitting = false; // Set when user selected Quit from menu, can be used by onPause, onStop, onDestroy
    private boolean mIsBind = false;
    
  //Sounds
    public static MediaPlayer mp;

    
    /**
     * True, when service is running.
     */
    private boolean mIsRunning;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "[ACTIVITY] onCreate");
        super.onCreate(savedInstanceState);
        
        //controle de volume
        setVolumeControlStream(AudioManager.STREAM_DTMF);
        
        mStepValue = 0;
        mPaceValue = 0;
        
        setContentView(R.layout.main);
        mUtils = Utils.getInstance();
    }
    
    @Override
    protected void onStart() {
        Log.i(TAG, "[ACTIVITY] onStart");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.i(TAG, "[ACTIVITY] onResume");
        super.onResume();
        //prepara audio
        mp = MediaPlayer.create(this, R.raw.annoying_alien_buzzer);
        
        mSettings = PreferenceManager.getDefaultSharedPreferences(this);
        mPedometerSettings = new PedometerSettings(mSettings);
        // Read from preferences if the service was running on the last onPause
        mIsRunning = mPedometerSettings.isServiceRunning();
        
        mPedometerSettings.clearServiceRunning();

        mStepValueView     = (TextView) findViewById(R.id.step_value);
        mPaceValueView     = (TextView) findViewById(R.id.pace_value);
        mDistanceValueView = (TextView) findViewById(R.id.distance_value);
        mSpeedValueView    = (TextView) findViewById(R.id.speed_value);
        mCaloriesValueView = (TextView) findViewById(R.id.calories_value);
        mTimeValueView	   = (Chronometer) findViewById(R.id.duracao_value);
        mProgress		   = (ProgressBar) findViewById(R.id.progressBar1);
        mBtTipoAtValueView = (ImageButton) findViewById(R.id.btTipoAt);
        mTxTipoAtValueView = (TextView) findViewById(R.id.textTipoAt);
        setTipoAt();
        
        //resta os valores se o chronometro for 00:00
        if(mTimeValueView.getText().toString().compareTo("00:00")==0){
        	resetValues(true);
        }

        mIsMetric = mPedometerSettings.isMetric();
        ((TextView) findViewById(R.id.distance_units)).setText(getString(
                mIsMetric
                ? R.string.kilometers
                : R.string.kilometers
        ));
        ((TextView) findViewById(R.id.speed_units)).setText(getString(
                mIsMetric
                ? R.string.kilometers_per_hour
                : R.string.kilometers_per_hour
        ));
        
    }
    
    private void setTipoAt() {
    	boolean isCorrendo = !mPedometerSettings.isRunning();
    	if(isCorrendo){
    		mBtTipoAtValueView.setBackgroundResource(R.drawable.icon_correndo);
    		mTxTipoAtValueView.setText("TIPO/ATIVIDADE\n"+"CORRENDO");
    	}else{
    		mBtTipoAtValueView.setBackgroundResource(R.drawable.icon_andando);
    		mTxTipoAtValueView.setText("TIPO/ATIVIDADE\n"+"ANDANDO");
    	}
		
	}

    @Override
    protected void onPause() {
        Log.i(TAG, "[ACTIVITY] onPause");
        if (mIsRunning) {
            unbindStepService();
        }
        if (mQuitting) {
            mPedometerSettings.saveServiceRunningWithNullTimestamp(mIsRunning);
        }
        else {
            mPedometerSettings.saveServiceRunningWithTimestamp(mIsRunning);
        }

        super.onPause();
        savePaceSetting();
    }

    @Override
    protected void onStop() {
        Log.i(TAG, "[ACTIVITY] onStop");
        super.onStop();
    }

    protected void onDestroy() {
        Log.i(TAG, "[ACTIVITY] onDestroy");
        super.onDestroy();
    }
    
    protected void onRestart() {
        Log.i(TAG, "[ACTIVITY] onRestart");
        super.onDestroy();
    }

    private void savePaceSetting() {
        mPedometerSettings.savePaceOrSpeedSetting(mMaintain, mDesiredPaceOrSpeed);
    }

    /*Service*/
    private StepService mService;
    
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = ((StepService.StepBinder)service).getService();

            mService.registerCallback(mCallback);
            mService.reloadSettings();
            
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
        }
    };
    

    private void startStepService() {
        if (! mIsRunning) {
            Log.i(TAG, "[SERVICE] Start");
            mIsRunning = true;
            startService(new Intent(Pedometer.this,
                    StepService.class));
        }
    }
    
    private void bindStepService() {
        Log.i(TAG, "[SERVICE] Bind");
        bindService(new Intent(Pedometer.this, 
                StepService.class), mConnection, Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND);
        mIsBind = true;
    }

    private void unbindStepService() {
        Log.i(TAG, "[SERVICE] Unbind");
        if(mIsBind){
        	unbindService(mConnection);
        	mIsBind = false;
        }
    }
    
    private void stopStepService() {
        Log.i(TAG, "[SERVICE] Stop");
        if (mService != null) {
            Log.i(TAG, "[SERVICE] stopService");
            stopService(new Intent(Pedometer.this,
                  StepService.class));
        }
        mIsRunning = false;
    }
    
    //botão pausar
    public void pausarAtividade(View view) {
    	//parar música
    	playStopedSound(false);
    	Button bPausar = (Button) findViewById(R.id.ButtonPausarAtividade);
    	if(mIsRunning){
    		unbindStepService();
            stopStepService();
            tempoParado = mTimeValueView.getBase()-SystemClock.elapsedRealtime();
            mTimeValueView.stop();

    		bPausar.setBackgroundResource(R.drawable.botoes_play);
    	}else{
            startStepService();
            bindStepService();
            if(mStepValueView.getText().equals("0")){
            }else{
            	mTimeValueView.setBase(SystemClock.elapsedRealtime()+tempoParado);
            	mTimeValueView.start();
            }
            
            bPausar.setBackgroundResource(R.drawable.botoes_pause);
    	}
        
    }
    
    //botão 'parar' (apresentará uma nova view com o resumo) e irá salvar o histórico
    public void pararAtividade(View view){
    	//para chronometro
    	mTimeValueView.stop();
    	//parar música
    	playStopedSound(false);
    	//monta os dados para a atividade
    	tempoAtividade = getMilliFromCrhonometer(mTimeValueView);
    	float horas = (float) ((float)tempoAtividade / 3600000);
    	velMedia = mDistanceValue/horas;
    	//formatando valor para uma casas depois da virgula
    	if(velMedia >= 0f && !Float.isInfinite(velMedia.floatValue())){
    		BigDecimal vMediaDecimal = new BigDecimal(velMedia.toString())
    		.setScale(1,BigDecimal.ROUND_HALF_DOWN);
    		velMedia = vMediaDecimal.floatValue();
    	}
    	
    	status = getStatus(mStepValue);
    	boolean tipoCorrendo = mPedometerSettings.isRunning();
    	String tipoAt = "andando";
    	if(!tipoCorrendo){
    		tipoAt = "correndo";
    	}else{
    		tipoAt = "andando";
    	}
    		
    	//pausar serviço e resetar valores 
    	if(mIsRunning)
    		pausarAtividade(view);
    	long data = this.data;
    	resetValues(true);
    	
    	//seta os dados no objeto atividade
    	Atividade atividade;
    	atividade = new Atividade();
    	atividade.setUser(getUsername());
    	atividade.setDate(data);
    	atividade.setTempoAtividade(tempoAtividade);
    	atividade.setPassos(mStepValue);
    	atividade.setRitmo(mPaceValue);
    	atividade.setDistancia(mDistanceValue);
    	atividade.setCalorias(mCaloriesValue);
    	atividade.setVelMedia(velMedia);
    	atividade.setStatus(status);
    	atividade.setTipo(tipoAt);
    	atividade.setIsSync(0);
    	
    	long id = -1l;
    	try {
    		DbHelper db = new DbHelper(this);
    		id = db.inserirAtividade(atividade);
		} catch (SQLiteException e) {
			System.out.println(e.toString());
		}
    	
		//popular o bundle para atrelar ao intent
    	atividade.setId(String.valueOf(id));
    	Bundle bAtividade = mUtils.atividadeToBundle(atividade);
    	
    	//chama a intent do resumo
    	Intent iResumo = new Intent(this, ResumoAtividade.class);
    	iResumo.putExtras(bAtividade);
    	startActivity(iResumo);
    }
    
	private long getMilliFromCrhonometer(Chronometer chrono) {
        long stoppedMilliseconds = 0;

        String chronoText = chrono.getText().toString();
        String array[] = chronoText.split(":");
        if (array.length == 2) {
            stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000
                    + Integer.parseInt(array[1]) * 1000;
        } else if (array.length == 3) {
            stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 60 * 1000
                    + Integer.parseInt(array[1]) * 60 * 1000
                    + Integer.parseInt(array[2]) * 1000;
        }

        return stoppedMilliseconds;
	}

	private String getStatus(int mStepValue) {
    	String status = "";
		if(mStepValue < 5000)
			status = "sedentario";
		else if(mStepValue >= 5000 && mStepValue < 7500)
			status = "baixa_atividade";
		else if(mStepValue >= 7500 && mStepValue < 10000)
			status = "pouca_atividade";
		else if(mStepValue >= 10000 && mStepValue < 12500)
			status = "ativa";
		else if(mStepValue >= 12500)
			status = "altamente_ativa";
		
		return status;
	}

	private void resetValues(boolean updateDisplay) {
        if (mService != null && mIsRunning) {
            mService.resetValues();                    
        }
        else {
            mStepValueView.setText("0");
            mPaceValueView.setText("0");
            mDistanceValueView.setText("0");
            mSpeedValueView.setText("0");
            mCaloriesValueView.setText("0");
            mTimeValueView.setText("00:00");
            tempoParado = 0l;
            mProgress.setProgress(0);
            data = 0l;
            SharedPreferences state = getSharedPreferences("state", 0);
            SharedPreferences.Editor stateEditor = state.edit();
            if (updateDisplay) {
                stateEditor.putInt("steps", 0);
                stateEditor.putInt("pace", 0);
                stateEditor.putFloat("distance", 0);
                stateEditor.putFloat("speed", 0);
                stateEditor.putFloat("calories", 0);
                stateEditor.putLong("time", 0l);
                stateEditor.commit();
            }
        }
    }

    private static final int MENU_SETTINGS = 8;
    private static final int MENU_QUIT     = 9;

    private static final int MENU_PAUSE = 1;
    private static final int MENU_RESUME = 2;
    private static final int MENU_RESET = 3;
    
    /* Creates the menu items */
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();
        if (mIsRunning) {
            menu.add(0, MENU_PAUSE, 0, R.string.pause)
            .setIcon(android.R.drawable.ic_media_pause)
            .setShortcut('1', 'p');
        }
        else {
            menu.add(0, MENU_RESUME, 0, R.string.resume)
            .setIcon(android.R.drawable.ic_media_play)
            .setShortcut('1', 'p');
        }
        menu.add(0, MENU_RESET, 0, R.string.reset)
        .setIcon(android.R.drawable.ic_menu_close_clear_cancel)
        .setShortcut('2', 'r');
        menu.add(0, MENU_SETTINGS, 0, R.string.settings)
        .setIcon(android.R.drawable.ic_menu_preferences)
        .setShortcut('8', 's')
        .setIntent(new Intent(this, Settings.class));
        menu.add(0, MENU_QUIT, 0, R.string.quit)
        .setIcon(android.R.drawable.ic_lock_power_off)
        .setShortcut('9', 'q');
        return true;
    }

    /* Handles item selections */
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_PAUSE:
                pausarAtividade(new View(this));
                return true;
            case MENU_RESUME:
            	pausarAtividade(new View(this));
                return true;
            case MENU_RESET:
                resetValues(true);
                return true;
            case MENU_QUIT:
                resetValues(false);
                unbindStepService();
                stopStepService();
                mQuitting = true;
                finish();
                return true;
        }
        return false;
    }
 
    // TODO: unite all into 1 type of message
    private StepService.ICallback mCallback = new StepService.ICallback() {
        public void stepsChanged(int value) {
            mHandler.sendMessage(mHandler.obtainMessage(STEPS_MSG, value, 0));
        }
        public void paceChanged(int value) {
            mHandler.sendMessage(mHandler.obtainMessage(PACE_MSG, value, 0));
        }
        public void distanceChanged(float value) {
            mHandler.sendMessage(mHandler.obtainMessage(DISTANCE_MSG, (int)(value*1000), 0));
        }
        public void speedChanged(float value) {
            mHandler.sendMessage(mHandler.obtainMessage(SPEED_MSG, (int)(value*1000), 0));
        }
        public void caloriesChanged(float value) {
            mHandler.sendMessage(mHandler.obtainMessage(CALORIES_MSG, (int)(value), 0));
        }
    };
    
    private static final int STEPS_MSG = 1;
    private static final int PACE_MSG = 2;
    private static final int DISTANCE_MSG = 3;
    private static final int SPEED_MSG = 4;
    private static final int CALORIES_MSG = 5;
    @SuppressWarnings("unused")
	private static final int STOP_MSG = 6;
    
    private Handler mHandler = new Handler() {
        @Override 
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case STEPS_MSG:
                    mStepValue = (int)msg.arg1;
                    mStepValueView.setText("" + mStepValue);
                    if(mStepValue == 1){
                    	data = Calendar.getInstance().getTimeInMillis();
                    	mTimeValueView.setBase(SystemClock.elapsedRealtime()+tempoParado);
                    	mTimeValueView.start();
                    }
                    refreshProgressBar(mStepValue);
                    break;
                case PACE_MSG:
                    mPaceValue = msg.arg1;
                    if (mPaceValue <= 0) { 
                        mPaceValueView.setText("0");
                    }
                    else {
                        mPaceValueView.setText("" + (int)mPaceValue);
                    }
                    break;
                case DISTANCE_MSG:
                    mDistanceValue = ((int)msg.arg1)/1000f;
                    if (mDistanceValue <= 0) { 
                        mDistanceValueView.setText("0");
                    }
                    else {
                        mDistanceValueView.setText(
                                ("" + (mDistanceValue + 0.000001f)).substring(0, 5)
                        );
                    }
                    break;
                case SPEED_MSG:
                    mSpeedValue = ((int)msg.arg1)/1000f;
                    if (mSpeedValue <= 0) { 
                        mSpeedValueView.setText("0");
                    }
                    else {
                        mSpeedValueView.setText(
                                ("" + (mSpeedValue + 0.000001f)).substring(0, 4)
                        );
                    }
                    break;
                case CALORIES_MSG:
                    mCaloriesValue = msg.arg1;
                    if (mCaloriesValue <= 0) { 
                        mCaloriesValueView.setText("0");
                    }
                    else {
                        mCaloriesValueView.setText("" + (int)mCaloriesValue);
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

		private void refreshProgressBar(int mStepValue) {
			if(mStepValue >=0 && mStepValue < 5000){
				if(mStepValue == 0){
					mProgress.setMax(5000);
				}
				mProgress.setProgress(mStepValue);
			}
			else if(mStepValue >= 5000 && mStepValue < 7500){
				if(mStepValue == 5000){
					mProgress.setVisibility(View.GONE);
					mProgress = (ProgressBar) findViewById(R.id.progressBar2);
					mProgress.setVisibility(View.VISIBLE);
					mProgress.setProgress(0);
					mProgress.setMax(2500);
				}
				mProgress.setProgress(mStepValue-5000);
			}
			else if(mStepValue >= 7500 && mStepValue < 10000){
				if(mStepValue == 7500){
					mProgress.setVisibility(View.GONE);
					mProgress = (ProgressBar) findViewById(R.id.progressBar3);
					mProgress.setVisibility(View.VISIBLE);
					mProgress.setProgress(0);
					mProgress.setMax(2500);
				}
				mProgress.setProgress(mStepValue-7500);
			}
			else if(mStepValue >= 10000 && mStepValue < 12500){
				if(mStepValue == 10000){
					mProgress.setVisibility(View.GONE);
					mProgress = (ProgressBar) findViewById(R.id.progressBar4);
					mProgress.setVisibility(View.VISIBLE);
					mProgress.setProgress(0);
					mProgress.setMax(2500);
				}
				mProgress.setProgress(mStepValue-1000);
			}
			else if(mStepValue >= 12500){
				if(mStepValue == 12500){
					mProgress.setVisibility(View.GONE);
					mProgress = (ProgressBar) findViewById(R.id.progressBar5);
					mProgress.setVisibility(View.VISIBLE);
					mProgress.setMax(5000);
				}
				mProgress.setProgress(mStepValue-12500);
			}
			
		}
        
    };
    
    public String getUsername(){
        AccountManager manager = AccountManager.get(this); 
        Account[] accounts = manager.getAccountsByType("com.google"); 
        List<String> possibleEmails = new LinkedList<String>();

        for (Account account : accounts) {
          // TODO: Check possibleEmail against an email regex or treat
          // account.name as an email address only for certain account.type values.
          possibleEmails.add(account.name);
        }

        if(!possibleEmails.isEmpty() && possibleEmails.get(0) != null){
            String email = possibleEmails.get(0);
            String[] parts = email.split("@");
            if(parts.length > 0 && parts[0] != null)
                return parts[0];
            else
                return null;
        }else
            return null;
    }

    public static void playStopedSound(boolean playSound) {
		if(playSound && !mp.isPlaying()){
			mp.start();
		}else if(mp.isPlaying()){
			mp.pause();
			mp.seekTo(0);
		}
		
	}
    

}